using System;
using System.Drawing;
using System.Windows.Forms; 

namespace Linquid
{
	/// <summary>
	/// Dialog built by combining layout produced by an UI action 
	/// with OK and Cancel buttons.
	/// </summary>
	public class Dialog<A>
	{
		private Form dialog;
		
		/// <summary>
		/// Result of the dialog. Only valid if the Show method returned true.
		/// </summary>
		public A Result {get; private set;}				
		
		/// <summary>
		/// Creates an OK/Cancel dialog from an UI action
		/// </summary>
		/// <param name="ui">Action to use</param>		
		public Dialog(UI<Source<A>> ui) : 
			this(form => ui) {}
		
		
		/// <summary>
		/// Creates an OK/Cancel dialog from an UI action.
		/// </summary>
		/// <param name="f">Function returning an UI action given the
		/// dialog's form. Can be used to set the form properties before 
		/// applying the layout.</param>
		public Dialog(Func<Form, UI<Source<A>>> f)
		{
			dialog = new Form()
			{				
				MaximizeBox = false,
				MinimizeBox = false,
				FormBorderStyle = FormBorderStyle.FixedDialog
			};
			
			var ui = f(dialog);
			
			var click = CreateMenu(dialog);
			
			var dialogUI =			
				from value in ui						 	
				let result =
					from x in value
					from c in click
					orderby click
					select new {x, c}
 			 	select result;
				
			dialogUI.Run(dialog).ValueChanged += item =>
			{			
				if (item.c)
				{
					Result = item.x;
					dialog.DialogResult = DialogResult.OK;
				}
				else
				{
					dialog.DialogResult = DialogResult.Cancel;
				}
				
				dialog.Close();
			};
		}				
		
		private Source<bool> CreateMenu(Form form)
		{
			var source = new Source<bool>();			
			
			var okButton = new MenuItem() {Text = "OK"};
			var cancelButton = new MenuItem() {Text = "Cancel"};
			var mainMenu = new MainMenu();

			okButton.Click += (s, a) => source.SetValue(true);
			cancelButton.Click += (s, a) => source.SetValue(false);
			
			mainMenu.MenuItems.Add(okButton);
			mainMenu.MenuItems.Add(cancelButton);
			form.Menu = mainMenu;
			
			return source;
		}		
		
		/// <summary>
		/// Shows the dialog
		/// </summary>
		/// <returns>true if OK was clicked, and false otherwise</returns>
		public bool Show()
		{
			return dialog.ShowDialog() == DialogResult.OK;
		}
	}
}